package org.lex.game.sudoku.view.cell;

import java.awt.Color;
import java.util.EnumMap;
import java.util.Map;

import ms.sudoku.util.IntSet;

import common.Sudokus;

public class CellRenderer {
	public static CellRenderer getDefault() {
		CellRenderer p = new CellRenderer();
		// foreground
		p.put(Face.FORE, CellStyle.NORMAL, Color.BLACK);
		p.put(Face.FORE, CellStyle.EDITABLE, Color.BLUE);
		p.put(Face.FORE, CellStyle.SELECTED, Color.BLACK);
		p.put(Face.FORE, CellStyle.HINTS, Color.LIGHT_GRAY);
		p.put(Face.FORE, CellStyle.ERROR, Color.BLACK);
		p.put(Face.FORE, CellStyle.HIGHLIGHT, Color.CYAN);

		// background
		p.put(Face.BACK, CellStyle.NORMAL, Color.LIGHT_GRAY);
		p.put(Face.BACK, CellStyle.EDITABLE, Color.WHITE);
		p.put(Face.BACK, CellStyle.SELECTED, Color.YELLOW);
		p.put(Face.BACK, CellStyle.HINTS, Color.WHITE);
		p.put(Face.BACK, CellStyle.ERROR, Color.RED);
		p.put(Face.BACK, CellStyle.HIGHLIGHT, Color.WHITE);
		return p;
	}

	public static enum Face {
		BACK(Color.WHITE), FORE(Color.BLACK);

		private final Color fallbackColor;

		private Face(Color fallbackColor) {
			this.fallbackColor = fallbackColor;
		}

		public Color getFallbackColor(Color defaultFg, Color defaultBg) {
			Color result = isFore() ? defaultFg : defaultBg;
			return null == result ? fallbackColor : result;
		}

		private boolean isFore() {
			return FORE == this;
		}
	}

	private Color fallbackFgColor = null;
	private Color fallbackBgColor = null;
	private Map<Face, Map<CellStyle, Color>> colors = new EnumMap<>(Face.class);

	public CellRenderer() {
	}

	public CellRenderer(Color fallbackFgColor, Color fallbackBgColor) {
		this.fallbackFgColor = fallbackFgColor;
		this.fallbackBgColor = fallbackBgColor;
	}

	public void setColor(CellView view, CellStyle style) {
		view.setForeground(this.get(Face.FORE, style));
		view.setBackground(this.get(Face.BACK, style));
	}

	public void put(Face face, CellStyle style, Color color) {
		Map<CellStyle, Color> faceColors = this.colors.get(face);
		if (null == faceColors) {
			faceColors = new EnumMap<>(CellStyle.class);
			this.colors.put(face, faceColors);
		}
		faceColors.put(style, color);
	}

	public Color get(Face face, CellStyle style) {
		Map<CellStyle, Color> faceColors = this.colors.get(face);
		if (null == faceColors) {
			faceColors = new EnumMap<>(CellStyle.class);
			this.colors.put(face, faceColors);
		}
		Color color = faceColors.get(style);
		if (null == color) {
			color = face.getFallbackColor(this.fallbackFgColor, this.fallbackBgColor);
			faceColors.put(style, color);
		}
		return color;
	}

	public String getDisplayText(int number, IntSet hints) {
		String result = "";
		if (Sudokus.EMPTY_NUMBER == number && null != hints) {
			// show hints
			StringBuilder buf = new StringBuilder();
			buf.append("<html><font size='-1' color='");
			this.color(this.get(Face.FORE, CellStyle.HINTS), buf);
			buf.append("'>");
			int i = 1;
			for (int num : hints) {
				buf.append(num);
				if (0 == i % 3) {
					i = 0;
					buf.append("<br/>");
				} else {
					if (i < hints.size() - 1) {
						buf.append(' ');
					}
				}
			}
			buf.append("</font></html>");
			result = buf.toString();
		} else {
			// show number only
			result = Integer.toString(number);
		}
		return result;
	}

	public static void main(String[] args) {
		CellRenderer p = new CellRenderer();
		StringBuilder buf = new StringBuilder();
		p.color(Color.DARK_GRAY, buf);
		System.out.println(buf);
	}

	private StringBuilder color(Color color, StringBuilder buf) {
		buf.append('#');
		int c = color.getRGB();
		for (int mask : COLOR_MASK) {
			int digit = c & mask;
			while (digit > 0xf) {
				digit >>= 4;
			}
			buf.append(Character.forDigit(digit, 16));
		}
		return buf;
	}

	private static final int[] COLOR_MASK = { 0xf00000, 0xf0000, 0xf000, 0xf00, 0xf0, 0xf };
}
